﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using InfFront.InfoViews.Base;
using InfFront.UICore;

namespace InfFront.InfoViews.WPF
{
    /// <summary>
    /// Interaction logic for MainFrame.xaml
    /// </summary>
    public partial class MainFrame : UserControl, IInfoViewPlatformCallbacks, IDisposable
    {
        #region Private Variables
        private Settings.Manager settings;
        private ProgressDialog currentProgressDialog;
        private RootInfoViewSource rootSource = null;
        #endregion

        #region Construction/Initialization
        public MainFrame()
        {
            InitializeComponent();
            Application.Current.DispatcherUnhandledException += DispatchUnhandledException;
        }

        public void SetSource(InfFront.UICore.IInfoSource source)
        {
            var src = new RootInfoViewSource(source, SettingsRoot);
            src.PlatformCallbacks = this;
            ViewSource = src;
        }

        public RootInfoViewSource ViewSource
        {
            get
            {
                return rootSource;
            }
            set
            {
                if (value == rootSource)
                    return;

                if (rootSource != null)
                    rootSource.VisualSettings.PropertyChanged -= this.rootSource_PropertyChanged;

                rootSource = value;
                DataContext = value;

                if (rootSource != null)
                    rootSource.VisualSettings.PropertyChanged += this.rootSource_PropertyChanged;

                Rebuild();
            }
        }

        #endregion

        private SettingsAccessor SettingsRoot
        {
            get
            {
                if (settings == null)
                {
                    var globals = new AppGlobals(this);
                    settings = new Settings.Manager(globals);
                }
                return settings.RootAccessor;
            }
        }

        private void Rebuild()
        {
            content.Content = null;
            if (rootSource == null)
                return;
            var vSettings = rootSource.VisualSettings;
            var style = (MainFrameStyle)vSettings.GetValue(Settings.Manager.MAIN_FRAME_STYLE_KEY);
            switch (style)
            {
                case MainFrameStyle.Explorer:
                    {
                        var template = new ExplorerFrame(rootSource);
                        content.Content = template;
                        break;
                    }
                case MainFrameStyle.MenuNTabs:
                    {
                        var template = new MenuTabsFrame(rootSource);
                        content.Content = template;
                        break;
                    }
                default:
                    throw new NotSupportedException(string.Format("Unknown MenuFrameStyle: {0}", style));
            }
        }

        #region Extensions

        public IExtensionProvider ExtensionProvider { get; set; }

        internal BaseSourceContentFrame SelectContentFrameFor(InfoViewSource source)
        {
            BaseSourceContentFrame result = null;
            if (ExtensionProvider != null)
                result = ExtensionProvider.CreateContentFrameFor(source);
            if (result == null)
            {
                if (source.MaxEntryCount == 0)
                    result = new CommandListFrame(source);
                else if (source.MaxEntryCount == 1)
                    result = new SingleEditWithToolbarFrame(source);
                else
                    result = new ListWithToolbarFrame(source);
            }
            return result;
        }

        #endregion Entensions

        #region Preference handling

        void rootSource_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == Settings.Manager.MAIN_FRAME_STYLE_KEY)
                Rebuild();
        }

        public void ShowPreferences(InfoViewSource selectedSource)
        {
            var wnd = new MainWindow();
            wnd.MainFrame.settings = settings;
            var infoSet = new Settings.SettingsInfoSet();
            infoSet.Title += " - " + rootSource.Title;
            infoSet.Source = rootSource;
            wnd.SetSource(infoSet);
            wnd.Owner = Application.Current.MainWindow;
            wnd.ShowInTaskbar = false;

            {
                var path = infoSet.TranslateInfoViewPathToSettingsPath((selectedSource != null) ? selectedSource.Path : null);
                wnd.MainFrame.ViewSource.VisualSettings.SetValue(Settings.Manager.LAST_SELECTED_SOURCE_KEY, path);
            }

            wnd.ShowDialog();
        }

        private void PreferencesMenuItem_Click(object sender, RoutedEventArgs e)
        {
            ShowPreferences(null);
        }

        #endregion Preference handling

        #region IInfoViewPlatformCallbacks Members

        void IInfoViewPlatformCallbacks.DisplayBackgroundWork(BackgroundWorker worker, IExecutionControl exec)
        {
            System.Diagnostics.Debug.Assert(currentProgressDialog == null);
            currentProgressDialog = new ProgressDialog(exec, DataContext);
            currentProgressDialog.Owner = Application.Current.MainWindow;
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(currentProgressDialog.OnRunWorkerCompleted);
            IsEnabled = false;
            currentProgressDialog.Start();
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            currentProgressDialog = null;
            IsEnabled = true;
        }

        void IInfoViewPlatformCallbacks.ExecInMainThread(AsyncCallMethod method, bool waitForFinish)
        {
            if (waitForFinish)
                Dispatcher.Invoke(method, null);
            else
                Dispatcher.BeginInvoke(method, null);
        }

        private delegate void ShowExceptionHandler(Exception ex);

        void IInfoViewPlatformCallbacks.HandleAsyncCallException(Exception ex)
        {
            Dispatcher.BeginInvoke(new ShowExceptionHandler(ShowException), ex);
        }

        #endregion

        #region Progress & Exception handling

        private class ProgressSuppressor : IDisposable
        {
            MainFrame owner;
            ProgressDialog savedProgress;

            public ProgressSuppressor(MainFrame frame)
            {
                this.owner = frame;
                this.savedProgress = frame.currentProgressDialog;
                if (savedProgress != null)
                {
                    savedProgress.Pause();
                    frame.currentProgressDialog = null;
                }
            }

            #region IDisposable Members

            public void Dispose()
            {
                if (savedProgress != null && !savedProgress.IsFinished)
                {
                    owner.currentProgressDialog = savedProgress;
                    savedProgress.Resume();
                }
            }

            #endregion
        }

        internal IDisposable SuppressProgress()
        {
            return new ProgressSuppressor(this);
        }

        private void ShowException(Exception ex)
        {
            InfoViewSource src = ViewSource; // TODO: maybe we should set the current InfoViewSource instead of root one here
            var dlg = new ErrorDialog(src, ex);
            var mainWnd = Application.Current.MainWindow;
            if (mainWnd != null && mainWnd.IsVisible)
                dlg.Owner = mainWnd;
            dlg.ShowDialog();
            if (mainWnd != null && !mainWnd.IsVisible)
                mainWnd.Close();
        }

        private void DispatchUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            if (e.Handled)
                return;
            Dispatcher.BeginInvoke(new ShowExceptionHandler(ShowException), e.Exception);
            e.Handled = true;
        }

        #endregion Progress handling

        #region IDisposable Members

        public void Dispose()
        {
            if (settings != null)
                settings.SaveDatabase();

            if (rootSource != null)
            {
                rootSource.Dispose();
                rootSource = null;
            }

            Application.Current.DispatcherUnhandledException -= DispatchUnhandledException;
        }

        #endregion
    }
}
